#include "dnfs.h"
#include "common.h"
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <getopt.h>
#include <sys/vfs.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include <sys/resource.h>

extern char OSDROOT[NAMELEN];
char NET_DEV[NAMELEN];
char MDS[IPLEN];
uint32_t localip;
#define SLEEP_TIME	5
#define OPEN_MAX	1024*1024
#define CONFIG_FILE	"dnfs-node.conf"
//#define STAT_LOG "stat_log"
#define CPUFILE "/proc/uptime"
#define MEMFILE	"/proc/meminfo" 
#define NETFILE "/proc/net/dev"
#define DISKFILE "/proc/diskstats"


float cpu_total, cpu_free, cpu_usage;
FILE *cpufile;
float getcpuusage()
{
	float last_total, last_free;
	last_total = cpu_total;
	last_free = cpu_free;
	
	if ((cpufile = fopen(CPUFILE,"r")) == NULL) {
		printf("can't open \"%s\".\n", CPUFILE);
		exit(1);
	}
	fscanf(cpufile, "%f%f", &cpu_total,&cpu_free);
	fclose(cpufile);
	
	cpu_usage=((cpu_total - last_total) - (cpu_free - last_free)) / (cpu_total - last_total);
	return cpu_usage;
}

FILE *memfile;
float mem_usage;
int mem_total;
float getmemusage()
{
	int memfree;
	if ((memfile = fopen(MEMFILE, "r")) == NULL) {
		printf("can't open \"%s\".\n", MEMFILE);
		exit(1);
	}	
	fscanf(memfile, "%*s%*d%*s%*s%d", &memfree);
	fclose(memfile);
	mem_usage = (float)(mem_total-memfree) / mem_total;
	return mem_usage;
}

struct netload {
	uint64_t r, t;
};

FILE *netfile;
double net_receive,net_transmit;
struct timeval net_f,net_l;
//int net_receive_load,net_transmit_load;
char buffer[1024*1024];

/*
 * 获取指定网卡接受与发送速度，以KByte为单位
 */
int getnetload (struct netload *res)
{
	uint64_t r, t;
	int dt_r, dt_t;
	float times;
	char *index;

	gettimeofday(&net_l, NULL);
	times = (float)(net_l.tv_sec - net_f.tv_sec) + (float)(net_l.tv_usec-net_f.tv_usec)/1000000;
	
	if ((netfile = fopen(NETFILE, "r")) == NULL) {
		printf("can't open %s .\n", NETFILE);
		exit(1);
	}
	//先把所有数据读进来
	if (fread(buffer, 1, sizeof(buffer), netfile) <= 0) {
		printf("read %s error\n", NETFILE);
		exit (2);
	}
	fclose(netfile);

	//定位到相应网络接口那一行
	if ((index = strstr(buffer, NET_DEV)) == NULL) {
		printf("Can't find the net device %s\n", NET_DEV);
		exit (3);
	}
	while (*index != ':')
		index++;
	index++;
	//unmask this line when you have more than one net device and want to detect the second one 
	//while(fgetc(netfile)!=':');
	sscanf(index, "%ld%*d%*d%*d%*d%*d%*d%*d%ld", &r, &t);
	dt_r = r - net_receive;
	dt_t = t - net_transmit;
//	net_receive_load = (int)((float)dt_r/times/1024);
//	net_transmit_load = (int)((float)dt_t/times/1024);
	res->r = (int)((float)dt_r/times/1024);
	res->t = (int)((float)dt_t/times/1024);
	//printf("%d/%f=%d\n",dt_r,times,net_receive_load);
	net_receive = r;
	net_transmit = t;
	net_f.tv_sec = net_l.tv_sec;
	net_f.tv_usec = net_f.tv_usec;
	
	return 0;
}

unsigned int sectors_read, sectors_write;
unsigned int sectors_read_f, sectors_write_f;
unsigned int sectors_read_l, sectors_write_l;
float read_speed, write_speed;
struct timeval disk_f,disk_l;	
struct diskload {
	uint64_t r, w;
};

/*
 * 获取的磁盘（分区）的读写速度，以KByte为单位
 */
int get_disk_stat(struct diskload *res) {
	gettimeofday(&disk_l, NULL);
	float time = (float)(disk_l.tv_sec - disk_f.tv_sec) + (float)(disk_l.tv_usec - disk_f.tv_usec)/1000000;
	char* index;
	
	FILE *fp;
	if ((fp = fopen(DISKFILE,"r")) == NULL) {
		printf("can't open %s\n", DISKFILE);
		exit(1);
	}
	fread(buffer, 1, sizeof(buffer), fp);
	
//	if ((index = strstr(buffer,disk_dev1)) == NULL ){
	if ((index = strstr(buffer, "sda1")) == NULL ) {
		printf("Can't find the disk device %s\n", "sda1");
		exit (4);
	}
	while (*index != ' ') index++;
	sscanf(index,"%*u%*u%u%*u%*u%*u%u", &sectors_read_l, &sectors_write_l);
//	printf("%u %u %u %u %u %u %u %u\n",read_issued_l,read_merged_l,sectors_read_l,\
		read_time_l, write_issued_l, write_merged_l, sectors_write_l, write_time_l);

	sectors_read = sectors_read_l - sectors_read_f;
	sectors_write = sectors_write_l - sectors_write_f;

	sectors_read_f = sectors_read_l  ;
	sectors_write_f = sectors_write_l  ;
	
//	printf("read sectors=%d\n", sectors_read);
//	printf("write sectors=%d\n", sectors_write);
//	read_speed=(float)sectors_read/2/time;// *512/1024/time
//	write_speed=(float)sectors_write/2/time;
	res->r = (float)sectors_read/2/time;
	res->w = (float)sectors_write/2/time;

	disk_f.tv_sec=disk_l.tv_sec;
	disk_f.tv_usec=disk_l.tv_usec;
	return 0;	
}


/*
 * 获得并返回文件系统的可用空间，以MByte为单位
 */
long get_avail_space()
{
	struct statfs buf;
	if (statfs(OSDROOT, &buf) != 0) {
		printf("statfs failed: %s\n", strerror(errno));
		return -1;
	}
	return buf.f_bavail * buf.f_bsize / 1024 / 1024;
}

void * load_detect()
{
	float cpu_usage;
	struct netload net_load;
	struct diskload disk_load;
	long avail_space;
	CLIENT	*cls;
	char *host = MDS;
	int res;
	os_loadreport_in arg;
	cls = clnt_create (host, OS, OS_VERS, "udp");
	if (cls == NULL) {
		clnt_pcreateerror (host);
		exit (1);
		//	return 1;
	}
	while (1) {
		cpu_usage = getcpuusage();
		getnetload(&net_load);
		get_disk_stat(&disk_load);
		avail_space = get_avail_space();	
		printf("[cpuusage] %f\t[net_receive] %ld\t[net_send] %ld\t[read_sectior] %ld\t[written_sector] %ld\t[avail_space] %ld\n", cpu_usage, net_load.r, net_load.t, disk_load.r, disk_load.w, avail_space);

		arg.cpu_usage = cpu_usage;
		arg.net_recv = net_load.r;
		arg.net_send = net_load.t;
		arg.disk_read = disk_load.r;
		arg.disk_write = disk_load.w;
		arg.avail_space = avail_space;
		arg.ipn = localip;
		printf("arg.ipn = %d\n", arg.ipn);
		if (os_loadreport_2(&arg, &res, cls) != RPC_SUCCESS) {
			printf("%s\n", clnt_sperror(cls, host));
			exit(-1);
		}
		sleep(SLEEP_TIME);
	}
	//should never get here
	clnt_destroy(cls);
}

int get_local_ip(uint32_t *ipn)
{	
	int s;
	struct ifconf conf;
       	struct ifreq *ifr;
       	char buff[4096];
       	int num;
       	int i;

       	s = socket(PF_INET, SOCK_DGRAM, 0);
       	conf.ifc_len = BUFSIZ;
       	conf.ifc_buf = buff;

       	ioctl(s, SIOCGIFCONF, &conf);
       	num = conf.ifc_len / sizeof(struct ifreq);
       	ifr = conf.ifc_req;
	
	char ipp[IPLEN];
       	for (i = 0; i < num; i++) {
               struct sockaddr_in *sin = (struct sockaddr_in *)(&ifr->ifr_addr);
               ioctl(s, SIOCGIFFLAGS, ifr);
               if(((ifr->ifr_flags & IFF_LOOPBACK) == 0) && (ifr->ifr_flags & IFF_UP)) {
			if (strcmp(ifr->ifr_name, NET_DEV) == 0) {
				printf("%s (%s)\n", ifr->ifr_name, inet_ntop(AF_INET, &sin->sin_addr, ipp, INET_ADDRSTRLEN));
				*ipn = sin->sin_addr.s_addr;
				printf("ipn = %d\n", *ipn);
			}
               }
               ifr++;
	}
	if (localip != 0)
		return 0;
	else 
		return -1;
}

int osd_init()
{
	FILE *fp;
	char type[LINELEN];
	char value[LINELEN];

	if ((fp = fopen(CONFIG_FILE, "r")) == NULL) {
		printf("can't open %s\n", CONFIG_FILE);
		return -1;
	}
	while (1) {
		if (fscanf(fp, "%s%s", type, value) != 2) {
			PDEBUG("init finish\n");
			break;
		}	
//		PDEBUG("%s %s\n", type, value);
		if (strcmp(type, "osdroot") == 0) {
			strcpy(OSDROOT, value);
			printf("OSDROOT = %s\n",  OSDROOT);
		}
		if (strcmp(type, "netinterface") == 0) {
			strcpy(NET_DEV, value);
			printf("NET_DEV = %s\n", NET_DEV);
		}
		if (strcmp(type, "MDS") == 0) {
			strcpy(MDS, value);
			printf("MDS = %s\n", MDS);
		}
	}
	get_local_ip(&localip);
	struct rlimit r;
    	int resource = RLIMIT_NOFILE;
    	printf("the original OPEN_MAX = %ld, ", sysconf(_SC_OPEN_MAX));
    	r.rlim_cur = OPEN_MAX;
    	r.rlim_max = OPEN_MAX;
    	if (setrlimit(resource, &r) != 0) {
    		printf("Set OPEN_MAX failed. Make sure you are ROOT!\n");
        	return -1;
    	}
	printf("set it to = %ld %ld\n", r.rlim_cur, r.rlim_max);
	
	int err;
	pthread_t tid;
	if ((err = pthread_create(&tid, NULL, load_detect, NULL)) != 0) {
		printf("create thread failed : %s\n", strerror(err));
	}
	return 0;
}

